/*
 *   Copyright 2021 zzh
 *
 *   Licensed under the Apache License, Version 2.0 (the "License");
 *   you may not use this file except in compliance with the License.
 *   You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *   Unless required by applicable law or agreed to in writing, software
 *   distributed under the License is distributed on an "AS IS" BASIS,
 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *   See the License for the specific language governing permissions and
 *   limitations under the License.
 *
 */

package com.aduib.boot.common.util;

import com.aduib.boot.common.compiler.JavaPattern;
import com.aduib.boot.common.exception.CommonException;
import com.aduib.boot.common.exception.IoException;
import com.aduib.boot.common.lang.Filter;
import com.aduib.boot.common.lang.NullWrapperBean;
import com.aduib.boot.common.lang.SimpleCache;

import java.io.Closeable;
import java.io.Externalizable;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.Serializable;
import java.io.StringWriter;
import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.net.URL;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.IdentityHashMap;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;

/**
 * @description: ClassUtils
 * @author: zzh
 * @date: 2021/9/8 10:30
 */
public final class ClassUtils {

  /** Suffix for array class names: {@code "[]"}. */
  public static final String ARRAY_SUFFIX = "[]";
  /** The CGLIB class separator: {@code "$$"}. */
  public static final String CGLIB_CLASS_SEPARATOR = "$$";
  /** The ".class" file suffix. */
  public static final String CLASS_FILE_SUFFIX = ".class";
  /** Prefix for internal array class names: {@code "["}. */
  private static final String INTERNAL_ARRAY_PREFIX = "[";
  /** Prefix for internal non-primitive array class names: {@code "[L"}. */
  private static final String NON_PRIMITIVE_ARRAY_PREFIX = "[L";
  /** A reusable empty class array constant. */
  private static final Class<?>[] EMPTY_CLASS_ARRAY = {};
  /** The package separator character: {@code '.'}. */
  private static final char PACKAGE_SEPARATOR = '.';
  /** The path separator character: {@code '/'}. */
  private static final char PATH_SEPARATOR = '/';
  /** The nested class separator character: {@code '$'}. */
  private static final char NESTED_CLASS_SEPARATOR = '$';
  /**
   * Map with primitive wrapper type as key and corresponding primitive type as value, for example:
   * Integer.class -> int.class.
   */
  private static final Map<Class<?>, Class<?>> primitiveWrapperTypeMap = new IdentityHashMap<>(9);

  /** 原始类型包含默认值 */
  private static final SimpleCache<Class<?>, Object> PRIMITIVE_TYPE_MAP = new SimpleCache<>();

  private static final Set<Class<?>> primitiveWrapperTypeSet = new LinkedHashSet<>();

  /**
   * Map with primitive type as key and corresponding wrapper type as value, for example: int.class
   * -> Integer.class.
   */
  private static final Map<Class<?>, Class<?>> primitiveTypeToWrapperMap = new IdentityHashMap<>(9);

  /**
   * Map with primitive type name as key and corresponding primitive type as value, for example:
   * "int" -> "int.class".
   */
  private static final Map<String, Class<?>> primitiveTypeNameMap = new HashMap<>(32);

  /**
   * Map with common Java language class name as key and corresponding Class as value. Primarily for
   * efficient deserialization of remote invocations.
   */
  private static final Map<String, Class<?>> commonClassCache = new HashMap<>(64);

  /**
   * Common Java language interfaces which are supposed to be ignored when searching for 'primary'
   * user-level interfaces.
   */
  private static final Set<Class<?>> javaLanguageInterfaces;

  /** 构造对象缓存 */
  private static final SimpleCache<Class<?>, Constructor<?>[]> CONSTRUCTORS_CACHE =
      new SimpleCache<>();

  /** 字段缓存 */
  private static final SimpleCache<Class<?>, Field[]> FIELDS_CACHE = new SimpleCache<>();
  /** 方法缓存 */
  private static final SimpleCache<Class<?>, Method[]> METHODS_CACHE = new SimpleCache<>();

  /** 本类方法缓存 */
  private static final SimpleCache<Class<?>, Method[]> DECLARED_METHODS_CACHE = new SimpleCache<>();

  static {
    // 添加默认值
    PRIMITIVE_TYPE_MAP.put(boolean.class, false);
    PRIMITIVE_TYPE_MAP.put(byte.class, 0);
    PRIMITIVE_TYPE_MAP.put(char.class, "");
    PRIMITIVE_TYPE_MAP.put(double.class, 0d);
    PRIMITIVE_TYPE_MAP.put(float.class, 0f);
    PRIMITIVE_TYPE_MAP.put(int.class, 0);
    PRIMITIVE_TYPE_MAP.put(long.class, 0);
    PRIMITIVE_TYPE_MAP.put(short.class, 0);

    /** 包装类型 */
    primitiveWrapperTypeSet.add(Boolean.class);
    primitiveWrapperTypeSet.add(Byte.class);
    primitiveWrapperTypeSet.add(Character.class);
    primitiveWrapperTypeSet.add(Double.class);
    primitiveWrapperTypeSet.add(Float.class);
    primitiveWrapperTypeSet.add(Integer.class);
    primitiveWrapperTypeSet.add(Long.class);
    primitiveWrapperTypeSet.add(Short.class);

    /** 包装类型对应原始类型 */
    primitiveWrapperTypeMap.put(Boolean.class, boolean.class);
    primitiveWrapperTypeMap.put(Byte.class, byte.class);
    primitiveWrapperTypeMap.put(Character.class, char.class);
    primitiveWrapperTypeMap.put(Double.class, double.class);
    primitiveWrapperTypeMap.put(Float.class, float.class);
    primitiveWrapperTypeMap.put(Integer.class, int.class);
    primitiveWrapperTypeMap.put(Long.class, long.class);
    primitiveWrapperTypeMap.put(Short.class, short.class);
    primitiveWrapperTypeMap.put(Void.class, void.class);

    // Map entry iteration is less expensive to initialize than forEach with lambdas
    for (Map.Entry<Class<?>, Class<?>> entry : primitiveWrapperTypeMap.entrySet()) {
      primitiveTypeToWrapperMap.put(entry.getValue(), entry.getKey());
      registerCommonClasses(entry.getKey());
    }

    Set<Class<?>> primitiveTypes = new HashSet<>(32);
    primitiveTypes.addAll(primitiveWrapperTypeMap.values());
    Collections.addAll(
        primitiveTypes,
        boolean[].class,
        byte[].class,
        char[].class,
        double[].class,
        float[].class,
        int[].class,
        long[].class,
        short[].class);
    for (Class<?> primitiveType : primitiveTypes) {
      primitiveTypeNameMap.put(primitiveType.getName(), primitiveType);
    }

    registerCommonClasses(
        Boolean[].class,
        Byte[].class,
        Character[].class,
        Double[].class,
        Float[].class,
        Integer[].class,
        Long[].class,
        Short[].class);
    registerCommonClasses(
        Number.class,
        Number[].class,
        String.class,
        String[].class,
        Class.class,
        Class[].class,
        Object.class,
        Object[].class);
    registerCommonClasses(
        Throwable.class,
        Exception.class,
        RuntimeException.class,
        Error.class,
        StackTraceElement.class,
        StackTraceElement[].class);
    registerCommonClasses(
        Enum.class,
        Iterable.class,
        Iterator.class,
        Enumeration.class,
        Collection.class,
        List.class,
        Set.class,
        Map.class,
        Map.Entry.class,
        Optional.class);

    Class<?>[] javaLanguageInterfaceArray = {
      Serializable.class,
      Externalizable.class,
      Closeable.class,
      AutoCloseable.class,
      Cloneable.class,
      Comparable.class
    };
    registerCommonClasses(javaLanguageInterfaceArray);
    javaLanguageInterfaces = new HashSet<>(Arrays.asList(javaLanguageInterfaceArray));
  }

  /** Register the given common classes with the ClassUtils cache. */
  private static void registerCommonClasses(Class<?>... commonClasses) {
    for (Class<?> clazz : commonClasses) {
      commonClassCache.put(clazz.getName(), clazz);
    }
  }

  public static Class<?> forName(String name, ClassLoader classLoader)
      throws IllegalArgumentException {
    try {
      return forName(name, false, classLoader);
    } catch (IllegalAccessError err) {
      throw new CommonException(
          "Readability mismatch in inheritance hierarchy of class ["
              + name
              + "]: "
              + err.getMessage(),
          err);
    } catch (LinkageError err) {
      throw new IllegalArgumentException(
          "Unresolvable class definition for class [" + name + "]", err);
    } catch (ClassNotFoundException e) {
      throw new IllegalArgumentException("Could not find class [" + name + "]", e);
    }
  }

  public static Class<?> forName(String name, boolean initialize, ClassLoader classLoader)
      throws ClassNotFoundException, LinkageError {
    Class<?> clazz = resolvePrimitiveClassName(name);
    if (clazz == null) {
      clazz = commonClassCache.get(name);
    }
    if (clazz != null) {
      return clazz;
    }

    // "java.lang.String[]" style arrays
    if (name.endsWith(ARRAY_SUFFIX)) {
      String elementClassName = name.substring(0, name.length() - ARRAY_SUFFIX.length());
      Class<?> elementClass = forName(elementClassName, initialize, classLoader);
      return Array.newInstance(elementClass, 0).getClass();
    }

    // "[Ljava.lang.String;" style arrays
    if (name.startsWith(NON_PRIMITIVE_ARRAY_PREFIX) && name.endsWith(";")) {
      String elementName = name.substring(NON_PRIMITIVE_ARRAY_PREFIX.length(), name.length() - 1);
      Class<?> elementClass = forName(elementName, initialize, classLoader);
      return Array.newInstance(elementClass, 0).getClass();
    }

    // "[[I" or "[[Ljava.lang.String;" style arrays
    if (name.startsWith(INTERNAL_ARRAY_PREFIX)) {
      String elementName = name.substring(INTERNAL_ARRAY_PREFIX.length());
      Class<?> elementClass = forName(elementName, initialize, classLoader);
      return Array.newInstance(elementClass, 0).getClass();
    }

    ClassLoader clToUse = classLoader;
    if (clToUse == null) {
      clToUse = getDefaultClassLoader();
    }
    try {
      return Class.forName(name, initialize, clToUse);
    } catch (ClassNotFoundException ex) {
      int lastDotIndex = name.lastIndexOf(PACKAGE_SEPARATOR);
      if (lastDotIndex != -1) {
        String nestedClassName =
            name.substring(0, lastDotIndex)
                + NESTED_CLASS_SEPARATOR
                + name.substring(lastDotIndex + 1);
        try {
          return Class.forName(nestedClassName, initialize, clToUse);
        } catch (ClassNotFoundException ex2) {
          // Swallow - let original exception get through
        }
      }
      throw ex;
    }
  }

  // --------------javassist-------------------//

  public static Class<?> forName(String[] packages, String className) {
    try {
      return classForName(className);
    } catch (ClassNotFoundException e) {
      if (packages != null && packages.length > 0) {
        for (String pkg : packages) {
          try {
            return classForName(pkg + "." + className);
          } catch (ClassNotFoundException ignore) {
          }
        }
      }
      throw new CommonException(e.getMessage(), e);
    }
  }

  public static Class<?> forName(String className) {
    try {
      return classForName(className);
    } catch (ClassNotFoundException e) {
      throw new CommonException(e.getMessage(), e);
    }
  }

  public static Class<?> classForName(String className) throws ClassNotFoundException {
    switch (className) {
      case "void":
        return void.class;
      case "boolean":
        return boolean.class;
      case "byte":
        return byte.class;
      case "char":
        return char.class;
      case "short":
        return short.class;
      case "int":
        return int.class;
      case "long":
        return long.class;
      case "float":
        return float.class;
      case "double":
        return double.class;
      case "boolean[]":
        return boolean[].class;
      case "byte[]":
        return byte[].class;
      case "char[]":
        return char[].class;
      case "short[]":
        return short[].class;
      case "int[]":
        return int[].class;
      case "long[]":
        return long[].class;
      case "float[]":
        return float[].class;
      case "double[]":
        return double[].class;
      default:
    }
    try {
      return arrayForName(className);
    } catch (ClassNotFoundException e) {
      // try to load from java.lang package
      if (className.indexOf('.') == -1) {
        try {
          return arrayForName("java.lang." + className);
        } catch (ClassNotFoundException ignore) {
          // ignore, let the original exception be thrown
        }
      }
      throw e;
    }
  }

  private static Class<?> arrayForName(String className) throws ClassNotFoundException {
    return Class.forName(
        className.endsWith("[]")
            ? "[L" + className.substring(0, className.length() - 2) + ";"
            : className,
        true,
        Thread.currentThread().getContextClassLoader());
  }

  /**
   * 通过字符串分割获取简单类名
   *
   * @param qualifiedName
   * @return
   */
  @Deprecated
  public static String getSimpleClassName(String qualifiedName) {
    if (null == qualifiedName) {
      return null;
    }
    int i = qualifiedName.lastIndexOf('.');
    return i < 0 ? qualifiedName : qualifiedName.substring(i + 1);
  }

  public static boolean isPresent(String className, ClassLoader classLoader) {
    try {
      forName(className, classLoader);
      return true;
    } catch (IllegalAccessError var3) {
      throw new CommonException(
          "Readability mismatch in inheritance hierarchy of class ["
              + className
              + "]: "
              + var3.getMessage(),
          var3);
    } catch (Throwable var4) {
      return false;
    }
  }

  public static boolean isVisible(Class<?> clazz, ClassLoader classLoader) {
    if (classLoader == null) {
      return true;
    } else {
      try {
        if (clazz.getClassLoader() == classLoader) {
          return true;
        }
      } catch (SecurityException var3) {
      }

      return isLoadable(clazz, classLoader);
    }
  }

  public static boolean isCacheSafe(Class<?> clazz, ClassLoader classLoader) {
    try {
      ClassLoader target = clazz.getClassLoader();
      if (target == classLoader || target == null) {
        return true;
      }

      if (classLoader == null) {
        return false;
      }

      ClassLoader current = classLoader;

      while (current != null) {
        current = current.getParent();
        if (current == target) {
          return true;
        }
      }

      while (target != null) {
        target = target.getParent();
        if (target == classLoader) {
          return false;
        }
      }
    } catch (SecurityException var4) {
    }

    return classLoader != null && isLoadable(clazz, classLoader);
  }

  private static boolean isLoadable(Class<?> clazz, ClassLoader classLoader) {
    try {
      return clazz == classLoader.loadClass(clazz.getName());
    } catch (ClassNotFoundException var3) {
      return false;
    }
  }

  /**
   * Resolve the given class name as primitive class, if appropriate, according to the JVM's naming
   * rules for primitive classes.
   *
   * <p>Also supports the JVM's internal class names for primitive arrays. Does <i>not</i> support
   * the "[]" suffix notation for primitive arrays; this is only supported by {@link
   * #forName(String, ClassLoader)}.
   *
   * @param name the name of the potentially primitive class
   * @return the primitive class, or {@code null} if the name does not denote a primitive class or
   *     primitive array class
   */
  public static Class<?> resolvePrimitiveClassName(String name) {
    Class<?> result = null;
    // Most class names will be quite long, considering that they
    // SHOULD sit in a package, so a length check is worthwhile.
    if (name != null && name.length() <= 7) {
      // Could be a primitive - likely.
      result = primitiveTypeNameMap.get(name);
    }
    return result;
  }

  /**
   * Return the default ClassLoader to use: typically the thread context ClassLoader, if available;
   * the ClassLoader that loaded the ClassUtils class will be used as fallback.
   *
   * <p>Call this method if you intend to use the thread context ClassLoader in a scenario where you
   * clearly prefer a non-null ClassLoader reference: for example, for class path resource loading
   * (but not necessarily for {@code Class.forName}, which accepts a {@code null} ClassLoader
   * reference as well).
   *
   * @return the default ClassLoader (only {@code null} if even the system ClassLoader isn't
   *     accessible)
   * @see Thread#getContextClassLoader()
   * @see ClassLoader#getSystemClassLoader()
   */
  public static ClassLoader getDefaultClassLoader(Class<?> clazz) {
    ClassLoader cl = null;
    try {
      cl = Thread.currentThread().getContextClassLoader();
    } catch (Throwable ex) {
      // Cannot access thread context ClassLoader - falling back...
    }
    if (cl == null) {
      // No thread context class loader -> use class loader of this class.
      cl = clazz.getClassLoader();
      if (cl == null) {
        // getClassLoader() returning null indicates the bootstrap ClassLoader
        try {
          cl = ClassLoader.getSystemClassLoader();
        } catch (Throwable ex) {
          // Cannot access system ClassLoader - oh well, maybe the caller can live with null...
        }
      }
    }
    return cl;
  }

  public static ClassLoader getDefaultClassLoader() {
    return getDefaultClassLoader(ClassUtils.class);
  }

  static ClassLoader getSystemClassLoader() {
    if (System.getSecurityManager() == null) {
      return ClassLoader.getSystemClassLoader();
    } else {
      return AccessController.doPrivileged(new PrivilegedAction<ClassLoader>() {
        @Override
        public ClassLoader run() {
          return ClassLoader.getSystemClassLoader();
        }
      });
    }
  }

  /**
   * Check if the given class represents a primitive wrapper, i.e. Boolean, Byte, Character, Short,
   * Integer, Long, Float, Double, or Void.
   *
   * @param clazz the class to check
   * @return whether the given class is a primitive wrapper class
   */
  public static boolean isPrimitiveWrapper(Class<?> clazz) {
    return primitiveWrapperTypeMap.containsKey(clazz);
  }

  /**
   * 指定类类型是否是原始类型
   *
   * @param clazz
   * @return
   */
  public static boolean isPrimitive(Class<?> clazz) {
    return PRIMITIVE_TYPE_MAP.containsKey(clazz);
  }

  /**
   * Check if the given class represents a primitive (i.e. boolean, byte, char, short, int, long,
   * float, or double), {@code void}, or a wrapper for those types (i.e. Boolean, Byte, Character,
   * Short, Integer, Long, Float, Double, or Void).
   *
   * @param clazz the class to check
   * @return {@code true} if the given class represents a primitive, void, or a wrapper class
   */
  public static boolean isPrimitiveOrWrapper(Class<?> clazz) {
    return (clazz.isPrimitive() || isPrimitiveWrapper(clazz));
  }

  /**
   * Check if the given class represents an array of primitives, i.e. boolean, byte, char, short,
   * int, long, float, or double.
   *
   * @param clazz the class to check
   * @return whether the given class is a primitive array class
   */
  public static boolean isPrimitiveArray(Class<?> clazz) {
    return (clazz.isArray() && clazz.getComponentType().isPrimitive());
  }

  /**
   * Check if the given class represents an array of primitive wrappers, i.e. Boolean, Byte,
   * Character, Short, Integer, Long, Float, or Double.
   *
   * @param clazz the class to check
   * @return whether the given class is a primitive wrapper array class
   */
  public static boolean isPrimitiveWrapperArray(Class<?> clazz) {
    return (clazz.isArray() && isPrimitiveWrapper(clazz.getComponentType()));
  }

  /**
   * 比较判断types1和types2两组类，如果types1中所有的类都与types2对应位置的类相同，或者是其父类或接口，则返回{@code true}
   *
   * @param types1 类组1
   * @param types2 类组2
   * @return 是否相同、父类或接口
   */
  public static boolean isAllAssignableFrom(Class<?>[] types1, Class<?>[] types2) {
    if (ArrayUtils.isEmpty(types1) && ArrayUtils.isEmpty(types2)) {
      return true;
    }
    if (null == types1 || null == types2) {
      // 任何一个为null不相等（之前已判断两个都为null的情况）
      return false;
    }
    if (types1.length != types2.length) {
      return false;
    }

    Class<?> type1;
    Class<?> type2;
    for (int i = 0; i < types1.length; i++) {
      type1 = types1[i];
      type2 = types2[i];
      if (isPrimitiveOrWrapper(type1) && isPrimitiveWrapper(type2)) {
        // 原始类型和包装类型存在不一致情况
        if (unWrap(type1) != unWrap(type2)) {
          return false;
        }
      } else if (false == type1.isAssignableFrom(type2)) {
        return false;
      }
    }
    return true;
  }

  /**
   * 检查指定类型是否为javaAPI的类
   *
   * @param clazz
   * @return
   */
  public static boolean isJdk(Class<?> clazz) {
    return clazz.getName().startsWith("java.") || clazz.getName().startsWith("javax.");
  }

  /**
   * 是否为静态方法
   *
   * @param method 方法
   * @return 是否为静态方法
   */
  public static boolean isStatic(Method method) {
    return Modifier.isStatic(method.getModifiers());
  }

  /**
   * 异常堆栈信息字符串转化
   *
   * @param e
   * @return
   */
  public static String stackTraceString(Throwable e) {
    StringWriter w = new StringWriter();
    PrintWriter p = new PrintWriter(w);
    p.print(e.getClass().getName() + ": ");
    if (e.getMessage() != null) {
      p.print(e.getMessage() + "\n");
    }
    p.println();
    try {
      e.printStackTrace(p);
      return w.toString();
    } finally {
      p.close();
    }
  }

  /**
   * 获取class文件路径
   *
   * @return
   */
  public static String getClassFilePath(Class<?> clazz) {
    return clazz.getResource("")
        + getSimpleClassName(clazz.getName())
        + JavaPattern.CLASS_EXTENSION;
  }

  /**
   * 获取所有classpath路径
   *
   * @return
   */
  public static List<URL> getClassPaths() {
    List<URL> urlList = new ArrayList<>();
    try {
      ClassLoader classLoader = getDefaultClassLoader();
      Enumeration<URL> resourcess = classLoader.getResources("");
      while (resourcess.hasMoreElements()) {
        urlList.add(resourcess.nextElement());
      }
    } catch (IOException e) {
      e.printStackTrace();
    }
    return urlList;
  }

  /**
   * 获取原始类型的默认值
   *
   * @param clazz
   * @return
   */
  public static Object getPrimitiveTypeValue(Class<?> clazz) {
    return PRIMITIVE_TYPE_MAP.get(clazz);
  }

  /**
   * 原始类转为包装类，非原始类返回原类
   *
   * @param clazz 原始类
   * @return 包装类
   */
  public static Class<?> wrap(Class<?> clazz) {
    if (null == clazz || false == clazz.isPrimitive()) {
      return clazz;
    }
    Class<?> result = primitiveTypeToWrapperMap.get(clazz);
    return (null == result) ? clazz : result;
  }

  /**
   * 包装类转为原始类，非包装类返回原类
   *
   * @param clazz 包装类
   * @return 原始类
   */
  public static Class<?> unWrap(Class<?> clazz) {
    if (null == clazz || clazz.isPrimitive()) {
      return clazz;
    }
    Class<?> result = primitiveWrapperTypeMap.get(clazz);
    return (null == result) ? clazz : result;
  }

  /**
   * 检查指定类型是否有默认构造器
   *
   * @param clazz
   * @return
   */
  public static boolean checkZeroArgConstructor(Class<?> clazz) {
    try {
      clazz.getDeclaredConstructor();
      return true;
    } catch (NoSuchMethodException e) {
      return false;
    }
  }

  /**
   * 寻找接口
   *
   * @param
   * @return
   */
  public static Class<?>[] getInterfaceClass(Class<?> clazz) {
    return clazz.getInterfaces();
  }

  /**
   * 寻找父类
   *
   * @param clazz
   * @return
   */
  public static Class<?> getSuperclass(Class<?> clazz) {
    return clazz.getSuperclass();
  }

  /**
   * 获取类名
   *
   * @param obj 获取类名对象
   * @param isSimple 是否简单类名，如果为true，返回不带包名的类名
   * @return 类名
   */
  public static String getClassName(Object obj, boolean isSimple) {
    if (null == obj) {
      return null;
    }
    final Class<?> clazz = obj.getClass();
    return getClassName(clazz, isSimple);
  }

  /**
   * 获取类名<br>
   * 类名并不包含“.class”这个扩展名<br>
   * 例如：ClassUtil这个类<br>
   *
   * <pre>
   * isSimple为false: "com.xiaoleilu.hutool.util.ClassUtil"
   * isSimple为true: "ClassUtil"
   * </pre>
   *
   * @param clazz 类
   * @param isSimple 是否简单类名，如果为true，返回不带包名的类名
   * @return 类名
   */
  public static String getClassName(Class<?> clazz, boolean isSimple) {
    if (null == clazz) {
      return null;
    }
    return isSimple ? clazz.getSimpleName() : clazz.getName();
  }

  /**
   * 获取完整类名的短格式如：<br>
   * cn.hutool.core.util.StrUtil -》c.h.c.u.StrUtil
   *
   * @param className 类名
   * @return 短格式类名
   */
  public static String getShortClassName(String className) {
    final List<String> packages = StrUtils.split(className, String.valueOf(CharUtils.DOT));
    if (null == packages || packages.size() < 2) {
      return className;
    }

    final int size = packages.size();
    final StringBuilder result = StrUtils.builder();
    result.append(packages.get(0).charAt(0));
    for (int i = 1; i < size - 1; i++) {
      result.append(CharUtils.DOT).append(packages.get(i).charAt(0));
    }
    result.append(CharUtils.DOT).append(packages.get(size - 1));
    return result.toString();
  }

  /**
   * 获得对象数组的类数组
   *
   * @param objects 对象数组，如果数组中存在{@code null}元素，则此元素被认为是Object类型
   * @return 类数组
   */
  public static Class<?>[] getClasses(Object... objects) {
    Class<?>[] classes = new Class<?>[objects.length];
    Object obj;
    for (int i = 0; i < objects.length; i++) {
      obj = objects[i];
      if (obj instanceof NullWrapperBean) {
        // 自定义null值的参数类型
        classes[i] = ((NullWrapperBean<?>) obj).getWrappedClass();
      } else if (null == obj) {
        classes[i] = Object.class;
      } else {
        classes[i] = obj.getClass();
      }
    }
    return classes;
  }
  /**
   * 执行实例方法
   *
   * @param target
   * @param method
   * @param args
   * @return
   * @throws CommonException
   */
  public static Object invoke(Object target, Method method, Object...args) throws CommonException {

    // Use reflection to invoke the method.
    try {
      setAccessible(method);
      return method.invoke(target, args);
    } catch (InvocationTargetException ex) {
      // Invoked method threw a checked exception.
      // We must rethrow it. The client won't see the interceptor.
      throw new CommonException(ex.getTargetException());
    } catch (IllegalArgumentException ex) {
      throw new CommonException(
          "seems to be invalid: tried calling method [" + method + "] on target [" + target + "]",
          ex);
    } catch (IllegalAccessException ex) {
      throw new CommonException("Could not access method [" + method + "]", ex);
    }
  }

  /**
   * 执行静态方法
   *
   * @param <T> 对象类型
   * @param method 方法（对象方法或static方法都可）
   * @param args 参数对象
   * @return 结果
   * @throws CommonException 多种异常包装
   */
  @SuppressWarnings("unchecked")
  public static <T> T invokeStatic(Method method, Object... args) throws CommonException {
    return (T) invoke(null, method, args);
  }

  /**
   * 执行方法
   *
   * @param target
   * @param method
   * @param args
   * @return
   * @throws CommonException
   */
  public static Object invokeMethod(Object target, Method method, Object...args) throws CommonException {
    if (isStatic(method)){
      return invokeStatic(method,args);
    }else{
      return invoke(target, method,args);
    }
  }

  /**
   * 设置为可访问（私有方法可以被外部调用）
   *
   * @param <T> AccessibleObject的子类，比如Class、Method、Field等
   * @param accessibleObject 可设置访问权限的对象，比如Class、Method、Field等
   * @return 被设置可访问的对象
   */
  public static <T extends AccessibleObject> T setAccessible(T accessibleObject) {
    if (null != accessibleObject && false == accessibleObject.isAccessible()) {
      accessibleObject.setAccessible(true);
    }
    return accessibleObject;
  }

  /**
   * 尝试设置可访问
   *
   * @param object
   * @param checkAccessible
   * @return
   */
  public static Throwable trySetAccessible(AccessibleObject object, boolean checkAccessible) {
    try {
      object.setAccessible(true);
      return null;
    } catch (SecurityException e) {
      return e;
    } catch (RuntimeException e) {
      return handleInaccessibleObjectException(e);
    }
  }

  private static RuntimeException handleInaccessibleObjectException(RuntimeException e) {
    // JDK 9 can throw an inaccessible object exception here; since Netty compiles
    // against JDK 7 and this exception was only added in JDK 9, we have to weakly
    // check the type
    if ("java.lang.reflect.InaccessibleObjectException".equals(e.getClass().getName())) {
      return e;
    }
    throw e;
  }

  /**
   * 查找类中的指定参数的构造方法，如果找到构造方法，会自动设置可访问为true
   *
   * @param <T> 对象类型
   * @param clazz 类
   * @param parameterTypes 参数类型，只要任何一个参数是指定参数的父类或接口或相等即可，此参数可以不传
   * @return 构造方法，如果未找到返回null
   */
  @SuppressWarnings("unchecked")
  public static <T> Constructor<T> getConstructor(Class<T> clazz, Class<?>... parameterTypes) {
    if (null == clazz) {
      return null;
    }

    final Constructor<?>[] constructors = getConstructors(clazz);
    Class<?>[] pts;
    for (Constructor<?> constructor : constructors) {
      pts = constructor.getParameterTypes();
      if (isAllAssignableFrom(pts, parameterTypes)) {
        // 构造可访问
        setAccessible(constructor);
        return (Constructor<T>) constructor;
      }
    }
    return null;
  }

  /**
   * 获得一个类中所有构造列表，直接反射获取，无缓存
   *
   * @param beanClass 类
   * @return 字段列表
   * @throws SecurityException 安全检查异常
   */
  public static Constructor<?>[] getConstructorsDirectly(Class<?> beanClass)
      throws SecurityException {
    return beanClass.getDeclaredConstructors();
  }

  /**
   * 获得一个类中所有构造列表
   *
   * @param <T> 构造的对象类型
   * @param beanClass 类
   * @return 字段列表
   * @throws SecurityException 安全检查异常
   */
  @SuppressWarnings("unchecked")
  public static <T> Constructor<T>[] getConstructors(Class<T> beanClass) throws SecurityException {
    Constructor<?>[] constructors = CONSTRUCTORS_CACHE.get(beanClass);
    if (null != constructors) {
      return (Constructor<T>[]) constructors;
    }

    constructors = getConstructorsDirectly(beanClass);
    return (Constructor<T>[]) CONSTRUCTORS_CACHE.put(beanClass, constructors);
  }

  // --------------------------------------------------------------------------------------------------------- Field

  public static boolean isStatic(Field field) {
    return Modifier.isStatic(field.getModifiers());
  }

  public static boolean isFinal(Field field) {
    return Modifier.isFinal(field.getModifiers());
  }

  /**
   * 查找指定类中是否包含指定名称对应的字段，包括所有字段（包括非public字段），也包括父类和Object类的字段
   *
   * @param beanClass 被查找字段的类,不能为null
   * @param name 字段名
   * @return 是否包含字段
   * @throws SecurityException 安全异常
   */
  public static boolean hasField(Class<?> beanClass, String name) throws SecurityException {
    return null != getField(beanClass, name);
  }

  /**
   * 获取字段名
   *
   * @param field 字段
   * @return 字段名
   */
  public static String getFieldName(Field field) {
    if (null == field) {
      return null;
    }

    return field.getName();
  }

  /**
   * 查找指定类中的指定name的字段（包括非public字段），也包括父类和Object类的字段， 字段不存在则返回{@code null}
   *
   * @param beanClass 被查找字段的类,不能为null
   * @param name 字段名
   * @return 字段
   * @throws SecurityException 安全异常
   */
  public static Field getField(Class<?> beanClass, String name) throws SecurityException {
    final Map<String, Field> fields = getFieldMap(beanClass);
    return fields.get(name);
  }

  /**
   * 获取指定类中字段名和字段对应的有序Map，包括其父类中的字段<br>
   * 如果子类与父类中存在同名字段，则这两个字段同时存在，子类字段在前，父类字段在后。
   *
   * @param beanClass 类
   * @return 字段名和字段对应的Map，有序
   */
  public static Map<String, Field> getFieldMap(Class<?> beanClass) {
    final Field[] fields = getFields(beanClass);
    final HashMap<String, Field> map = MapUtils.newHashMap(fields.length, true);
    for (Field field : fields) {
      map.put(field.getName(), field);
    }
    return map;
  }

  /**
   * 获得一个类中所有字段列表，包括其父类中的字段<br>
   * 如果子类与父类中存在同名字段，则这两个字段同时存在，子类字段在前，父类字段在后。
   *
   * @param beanClass 类
   * @return 字段列表
   * @throws SecurityException 安全检查异常
   */
  public static Field[] getFields(Class<?> beanClass) throws SecurityException {
    Field[] allFields = FIELDS_CACHE.get(beanClass);
    if (null != allFields) {
      return allFields;
    }

    allFields = getFieldsDirectly(beanClass, true);
    return FIELDS_CACHE.put(beanClass, allFields);
  }

  /**
   * 获得一个类中所有字段列表，直接反射获取，无缓存<br>
   * 如果子类与父类中存在同名字段，则这两个字段同时存在，子类字段在前，父类字段在后。
   *
   * @param beanClass 类
   * @param withSuperClassFields 是否包括父类的字段列表
   * @return 字段列表
   * @throws SecurityException 安全检查异常
   */
  public static Field[] getFieldsDirectly(Class<?> beanClass, boolean withSuperClassFields)
      throws SecurityException {

    Field[] allFields = null;
    Class<?> searchType = beanClass;
    Field[] declaredFields;
    while (searchType != null) {
      declaredFields = searchType.getDeclaredFields();
      if (null == allFields) {
        allFields = declaredFields;
      } else {
        allFields = ArrayUtils.append(allFields, declaredFields);
      }
      searchType = withSuperClassFields ? searchType.getSuperclass() : null;
    }

    return allFields;
  }

  /**
   * 获取字段值
   *
   * @param obj 对象，如果static字段，此处为类
   * @param fieldName 字段名
   * @return 字段值
   * @throws CommonException 包装IllegalAccessException异常
   */
  public static Object getFieldValue(Object obj, String fieldName) throws CommonException {
    if (null == obj || StrUtils.isBlank(fieldName)) {
      return null;
    }
    return getFieldValue(
        obj, getField(obj instanceof Class ? (Class<?>) obj : obj.getClass(), fieldName));
  }

  /**
   * 获取静态字段值
   *
   * @param field 字段
   * @return 字段值
   * @throws CommonException 包装IllegalAccessException异常
   */
  public static Object getStaticFieldValue(Field field) throws CommonException {
    return getFieldValue(null, field);
  }

  /**
   * 获取字段值
   *
   * @param obj 对象，static字段则此字段为null
   * @param field 字段
   * @return 字段值
   * @throws CommonException 包装IllegalAccessException异常
   */
  public static Object getFieldValue(Object obj, Field field) throws CommonException {
    if (null == field) {
      return null;
    }
    if (obj instanceof Class) {
      // 静态字段获取时对象为null
      obj = null;
    }

    setAccessible(field);
    Object result;
    try {
      result = field.get(obj);
    } catch (IllegalAccessException e) {
      throw new CommonException(
          e, "IllegalAccess for {}.{}", field.getDeclaringClass(), field.getName());
    }
    return result;
  }

  /**
   * 获取所有字段的值
   *
   * @param obj bean对象，如果是static字段，此处为类class
   * @return 字段值数组
   */
  public static Object[] getFieldsValue(Object obj) {
    if (null != obj) {
      final Field[] fields = getFields(obj instanceof Class ? (Class<?>) obj : obj.getClass());
      if (null != fields) {
        final Object[] values = new Object[fields.length];
        for (int i = 0; i < fields.length; i++) {
          values[i] = getFieldValue(obj, fields[i]);
        }
        return values;
      }
    }
    return null;
  }

  /**
   * 设置字段值
   *
   * @param obj 对象,static字段则此处传Class
   * @param fieldName 字段名
   * @param value 值，值类型必须与字段类型匹配，不会自动转换对象类型
   * @throws CommonException 包装IllegalAccessException异常
   */
  public static void setFieldValue(Object obj, String fieldName, Object value)
      throws CommonException {
    final Field field =
        getField((obj instanceof Class) ? (Class<?>) obj : obj.getClass(), fieldName);
    setFieldValue(obj, field, value);
  }

  /**
   * 设置字段值
   *
   * @param obj 对象，如果是static字段，此参数为null
   * @param field 字段
   * @param value 值，值类型必须与字段类型匹配，不会自动转换对象类型
   * @throws CommonException CommonException 包装IllegalAccessException异常
   */
  public static void setFieldValue(Object obj, Field field, Object value) throws CommonException {

    final Class<?> fieldType = field.getType();
    if (null != value) {
      if (false == fieldType.isAssignableFrom(value.getClass())) {
        final Object targetValue = value;
        if (null != targetValue) {
          value = targetValue;
        }
      }
    } else {
      // 获取null对应默认值，防止原始类型造成空指针问题
      value = getPrimitiveTypeValue(fieldType);
    }

    setAccessible(field);
    try {
      field.set(obj instanceof Class ? null : obj, value);
    } catch (IllegalAccessException e) {
      throw new CommonException(e, "IllegalAccess for {}.{}", obj, field.getName());
    }
  }

  /**
   * 实例化对象
   *
   * @param <T> 对象类型
   * @param clazz 类
   * @param params 构造函数参数
   * @return 对象
   * @throws CommonException 包装各类异常
   */
  public static <T> T newInstance(Class<T> clazz, Object... params) throws CommonException {
    if (ArrayUtils.isEmpty(params)) {
      final Constructor<T> constructor = getConstructor(clazz);
      try {
        return constructor.newInstance();
      } catch (Exception e) {
        throw new CommonException(e, "Instance class [{}] error!", clazz);
      }
    }

    final Class<?>[] paramTypes = getClasses(params);
    final Constructor<T> constructor = getConstructor(clazz, paramTypes);
    if (null == constructor) {
      throw new CommonException(
          "No Constructor matched for parameter types: [{}]", new Object[] {paramTypes});
    }
    try {
      return constructor.newInstance(params);
    } catch (Exception e) {
      throw new CommonException(e, "Instance class [{}] error!", clazz);
    }
  }

  @SuppressWarnings("unchecked")
  public static <T> T newInstance(final Constructor<T> constructor, Object[] params) {
    Class<? extends AccessibleObject> clazz = constructor.getClass();
    if (ArrayUtils.isEmpty(params)) {
      try {
        return constructor.newInstance();
      } catch (Exception e) {
        throw new CommonException(e, "Instance class [{}] error!", clazz);
      }
    }
    try {
      return constructor.newInstance(params);
    } catch (Exception e) {
      throw new CommonException(e, "Instance class [{}] error!", clazz);
    }
  }

  // --------------------------------------------------------------------------------------------------------- method

  //判断是否是set方法
  private boolean isSetter(Method method) {
    return method.getName().startsWith("set")
            && method.getParameterTypes().length == 1F
            && Modifier.isPublic(method.getModifiers());
  }

  /**
   * 获得指定类本类及其父类中的Public方法名<br>
   * 去重重载的方法
   *
   * @param clazz 类
   * @return 方法名Set
   */
  public static Set<String> getPublicMethodNames(Class<?> clazz) {
    final HashSet<String> methodSet = new HashSet<>();
    final Method[] methodArray = getPublicMethods(clazz);
    if (ArrayUtils.isNotEmpty(methodArray)) {
      for (Method method : methodArray) {
        methodSet.add(method.getName());
      }
    }
    return methodSet;
  }

  /**
   * 获得本类及其父类所有Public方法
   *
   * @param clazz 查找方法的类
   * @return 过滤后的方法列表
   */
  public static Method[] getPublicMethods(Class<?> clazz) {
    return null == clazz ? null : clazz.getMethods();
  }

  /**
   * 获得指定类过滤后的Public方法列表
   *
   * @param clazz 查找方法的类
   * @param filter 过滤器
   * @return 过滤后的方法列表
   */
  public static List<Method> getPublicMethods(Class<?> clazz, Filter<Method> filter) {
    if (null == clazz) {
      return null;
    }

    final Method[] methods = getPublicMethods(clazz);
    List<Method> methodList;
    if (null != filter) {
      methodList = new ArrayList<>();
      for (Method method : methods) {
        if (filter.accept(method)) {
          methodList.add(method);
        }
      }
    } else {
      methodList = ListUtils.toList(methods);
    }
    return methodList;
  }

  /**
   * 获得指定类过滤后的Public方法列表
   *
   * @param clazz 查找方法的类
   * @param excludeMethods 不包括的方法
   * @return 过滤后的方法列表
   */
  public static List<Method> getPublicMethods(Class<?> clazz, Method... excludeMethods) {
    final HashSet<Method> excludeMethodSet = MapUtils.newHashSet(excludeMethods);
    return getPublicMethods(clazz, method -> false == excludeMethodSet.contains(method));
  }

  /**
   * 获得指定类过滤后的Public方法列表
   *
   * @param clazz 查找方法的类
   * @param excludeMethodNames 不包括的方法名列表
   * @return 过滤后的方法列表
   */
  public static List<Method> getPublicMethods(Class<?> clazz, String... excludeMethodNames) {
    final HashSet<String> excludeMethodNameSet = MapUtils.newHashSet(excludeMethodNames);
    return getPublicMethods(
        clazz, method -> false == excludeMethodNameSet.contains(method.getName()));
  }

  /**
   * 查找指定Public方法 如果找不到对应的方法或方法不为public的则返回{@code null}
   *
   * @param clazz 类
   * @param methodName 方法名
   * @param paramTypes 参数类型
   * @return 方法
   * @throws SecurityException 无权访问抛出异常
   */
  public static Method getPublicMethod(Class<?> clazz, String methodName, Class<?>... paramTypes)
      throws SecurityException {
    try {
      return clazz.getMethod(methodName, paramTypes);
    } catch (NoSuchMethodException ex) {
      return null;
    }
  }

  /**
   * 查找指定对象中的所有方法（包括非public方法），也包括父对象和Object类的方法
   *
   * <p>此方法为精准获取方法名，即方法名和参数数量和类型必须一致，否则返回{@code null}。
   *
   * @param obj 被查找的对象，如果为{@code null}返回{@code null}
   * @param methodName 方法名，如果为空字符串返回{@code null}
   * @param args 参数
   * @return 方法
   * @throws SecurityException 无访问权限抛出异常
   */
  public static Method getMethodOfObj(Object obj, String methodName, Object... args)
      throws SecurityException {
    if (null == obj || StrUtils.isBlank(methodName)) {
      return null;
    }
    return getMethod(obj.getClass(), methodName, getClasses(args));
  }

  /**
   * 忽略大小写查找指定方法，如果找不到对应的方法则返回{@code null}
   *
   * <p>此方法为精准获取方法名，即方法名和参数数量和类型必须一致，否则返回{@code null}。
   *
   * @param clazz 类，如果为{@code null}返回{@code null}
   * @param methodName 方法名，如果为空字符串返回{@code null}
   * @param paramTypes 参数类型，指定参数类型如果是方法的子类也算
   * @return 方法
   * @throws SecurityException 无权访问抛出异常
   */
  public static Method getMethodIgnoreCase(
      Class<?> clazz, String methodName, Class<?>... paramTypes) throws SecurityException {
    return getMethod(clazz, true, methodName, paramTypes);
  }

  /**
   * 查找指定方法 如果找不到对应的方法则返回{@code null}
   *
   * <p>此方法为精准获取方法名，即方法名和参数数量和类型必须一致，否则返回{@code null}。
   *
   * @param clazz 类，如果为{@code null}返回{@code null}
   * @param methodName 方法名，如果为空字符串返回{@code null}
   * @param paramTypes 参数类型，指定参数类型如果是方法的子类也算
   * @return 方法
   * @throws SecurityException 无权访问抛出异常
   */
  public static Method getMethod(Class<?> clazz, String methodName, Class<?>... paramTypes)
      throws SecurityException {
    return getMethod(clazz, false, methodName, paramTypes);
  }

  /**
   * 查找指定方法 如果找不到对应的方法则返回{@code null}
   *
   * <p>此方法为精准获取方法名，即方法名和参数数量和类型必须一致，否则返回{@code null}。
   *
   * @param clazz 类，如果为{@code null}返回{@code null}
   * @param ignoreCase 是否忽略大小写
   * @param methodName 方法名，如果为空字符串返回{@code null}
   * @param paramTypes 参数类型，指定参数类型如果是方法的子类也算
   * @return 方法
   * @throws SecurityException 无权访问抛出异常
   */
  public static Method getMethod(
      Class<?> clazz, boolean ignoreCase, String methodName, Class<?>... paramTypes)
      throws SecurityException {
    if (null == clazz || StrUtils.isBlank(methodName)) {
      return null;
    }

    final Method[] methods = getMethods(clazz);
    if (ArrayUtils.isNotEmpty(methods)) {
      for (Method method : methods) {
        if (StrUtils.equals(methodName, method.getName(), ignoreCase)) {
          if (isAllAssignableFrom(method.getParameterTypes(), paramTypes)) {
            return method;
          }
        }
      }
    }
    return null;
  }

  /**
   * 按照方法名查找指定方法名的方法，只返回匹配到的第一个方法，如果找不到对应的方法则返回{@code null}
   *
   * <p>此方法只检查方法名是否一致，并不检查参数的一致性。
   *
   * @param clazz 类，如果为{@code null}返回{@code null}
   * @param methodName 方法名，如果为空字符串返回{@code null}
   * @return 方法
   * @throws SecurityException 无权访问抛出异常
   */
  public static Method getMethodByName(Class<?> clazz, String methodName) throws SecurityException {
    return getMethodByName(clazz, false, methodName);
  }

  /**
   * 按照方法名查找指定方法名的方法，只返回匹配到的第一个方法，如果找不到对应的方法则返回{@code null}
   *
   * <p>此方法只检查方法名是否一致（忽略大小写），并不检查参数的一致性。
   *
   * @param clazz 类，如果为{@code null}返回{@code null}
   * @param methodName 方法名，如果为空字符串返回{@code null}
   * @return 方法
   * @throws SecurityException 无权访问抛出异常
   */
  public static Method getMethodByNameIgnoreCase(Class<?> clazz, String methodName)
      throws SecurityException {
    return getMethodByName(clazz, true, methodName);
  }

  /**
   * 按照方法名查找指定方法名的方法，只返回匹配到的第一个方法，如果找不到对应的方法则返回{@code null}
   *
   * <p>此方法只检查方法名是否一致，并不检查参数的一致性。
   *
   * @param clazz 类，如果为{@code null}返回{@code null}
   * @param ignoreCase 是否忽略大小写
   * @param methodName 方法名，如果为空字符串返回{@code null}
   * @return 方法
   * @throws SecurityException 无权访问抛出异常
   */
  public static Method getMethodByName(Class<?> clazz, boolean ignoreCase, String methodName)
      throws SecurityException {
    if (null == clazz || StrUtils.isBlank(methodName)) {
      return null;
    }

    final Method[] methods = getMethods(clazz);
    if (ArrayUtils.isNotEmpty(methods)) {
      for (Method method : methods) {
        if (StrUtils.equals(methodName, method.getName(), ignoreCase)) {
          return method;
        }
      }
    }
    return null;
  }

  /**
   * 获得指定类中的Public方法名<br>
   * 去重重载的方法
   *
   * @param clazz 类
   * @return 方法名Set
   * @throws SecurityException 安全异常
   */
  public static Set<String> getMethodNames(Class<?> clazz) throws SecurityException {
    final HashSet<String> methodSet = new HashSet<>();
    final Method[] methods = getMethods(clazz);
    for (Method method : methods) {
      methodSet.add(method.getName());
    }
    return methodSet;
  }

  /**
   * 获得一个类中所有方法列表，包括其父类中的方法
   *
   * @param beanClass 类
   * @return 方法列表
   * @throws SecurityException 安全检查异常
   */
  public static Method[] getMethods(Class<?> beanClass) throws SecurityException {
    Method[] allMethods = METHODS_CACHE.get(beanClass);
    if (null != allMethods) {
      return allMethods;
    }

    allMethods = getMethodsDirectly(beanClass, true);
    return METHODS_CACHE.put(beanClass, allMethods);
  }

  /**
   * 获得一个类中所有方法列表
   *
   * @param beanClass 类
   * @return 方法列表
   * @throws SecurityException 安全检查异常
   */
  public static Method[] getDeclaredMethods(Class<?> beanClass) throws SecurityException {
    Method[] allMethods = DECLARED_METHODS_CACHE.get(beanClass);
    if (null != allMethods) {
      return allMethods;
    }

    allMethods = getMethodsDirectly(beanClass, false);
    return DECLARED_METHODS_CACHE.put(beanClass, allMethods);
  }

  /**
   * 获得一个类中所有方法列表，直接反射获取，无缓存
   *
   * @param beanClass 类
   * @param withSuperClassMethods 是否包括父类的方法列表
   * @return 方法列表
   * @throws SecurityException 安全检查异常
   */
  public static Method[] getMethodsDirectly(Class<?> beanClass, boolean withSuperClassMethods)
      throws SecurityException {

    Method[] allMethods = null;
    Class<?> searchType = beanClass;
    Method[] declaredMethods;
    while (searchType != null) {
      declaredMethods = searchType.getDeclaredMethods();
      if (null == allMethods) {
        allMethods = declaredMethods;
      } else {
        allMethods = ArrayUtils.append(allMethods, declaredMethods);
      }
      searchType = withSuperClassMethods ? searchType.getSuperclass() : null;
    }

    return allMethods;
  }

  /**
   * 是否为equals方法
   *
   * @param method 方法
   * @return 是否为equals方法
   */
  public static boolean isEqualsMethod(Method method) {
    if (method == null || false == "equals".equals(method.getName())) {
      return false;
    }
    final Class<?>[] paramTypes = method.getParameterTypes();
    return (1 == paramTypes.length && paramTypes[0] == Object.class);
  }

  /**
   * 是否为hashCode方法
   *
   * @param method 方法
   * @return 是否为hashCode方法
   */
  public static boolean isHashCodeMethod(Method method) {
    return method != null //
        && "hashCode".equals(method.getName()) //
        && isEmptyParam(method);
  }

  /**
   * 是否为toString方法
   *
   * @param method 方法
   * @return 是否为toString方法
   */
  public static boolean isToStringMethod(Method method) {
    return method != null //
        && "toString".equals(method.getName()) //
        && isEmptyParam(method);
  }

  /**
   * 是否为无参数方法
   *
   * @param method 方法
   * @return 是否为无参数方法
   */
  public static boolean isEmptyParam(Method method) {
    return method.getParameterTypes().length == 0;
  }

  /**
   * @param resource
   * @param baseClass
   * @return
   */
  public static URL getResource(String resource, Class<?> baseClass) {
    return (null != baseClass) ? baseClass.getResource(resource) : getDefaultClassLoader().getResource(resource);
  }

  /**
   * 获得资源的URL<br>
   * 路径用/分隔，例如:
   *
   * <pre>
   * config/a/db.config
   * spring/xml/test.xml
   * </pre>
   *
   * @param resource 资源（相对Classpath的路径）
   * @return 资源URL
   */
  public static URL getResource(String resource) throws IoException {
    return getResource(resource, null);
  }

  /**
   * 获得ClassPath URL
   *
   * @return ClassPath URL
   */
  public static URL getClassPathURL() {
    return getResource(StrUtils.EMPTY);
  }

  /**
   * @return 获得Java ClassPath路径，不包括 jre
   */
  public static String[] getJavaClassPaths() {
    return SystemUtils.getStringValue("java.class.path").split(SystemUtils.getStringValue("path.separator"));
  }
}
